perm filename TRY.PAS[P,JRA] blob sn#438149 filedate 1979-04-29 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00002 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	(*pascal programs*)
C00023 ENDMK
C⊗;
(*pascal programs*)
(*$E+*)
program junk,unify,subst,replace,copytermlist,copyterm,copyconst,copysym;
(*pascal can't handle things the way it should so we have to invent strange
	names that are all referring to the same thing, in particular, the type
	of the object at hand. Thus,
	alltyps, an indication of the possible atomic types, is actually made
		up of convoluted versions of the type names.
	this idiocy is carried on throughout, which is why you'll see several
	different names that all look similar but had to be different for pascal. *)

TYPE
	(* alltyps are the types of atomic constants *)
	alltyps = (integertyp, realtyp, booleantyp, chartyp, symboltyp);

	termtyps = (variable, constanttyp, funapp);

	term = ↑t1;

	termlist = ↑tl1;

	constant = ↑c1;

	symbol = ↑sym1;

	t1 = record
		case ttyp:termtyps of
			variable: (vr: integer);
			constanttyp: (cnst: constant);
			funapp:   (fname: symbol;
				   args: termlist)
		end;

	tl1 = record
		notempty: boolean;
		first: term;
		rest: termlist
		end;


		(*changed again: a variable is just an integer, serves fine for
			comparison and we never print them out anyway*)

(*	variable = symbol;	*)	(*vars have names and are free, when they 
					get bound they are replaced by other terms*)

(*	variable = ↑v1;

	v1 = record
		bound: boolean;
		pname: symbol;
		case vtyp:alltyps of
			integer: (ival: integer);
			real:    (rval: real);
			boolean: (bval: boolean);
			char:	 (cval: char);
			term:	 (tval: term)
		end;				*)

	c1 = record
		case ctyp:alltyps of
			integertyp: (ival: integer);
			realtyp:    (rval: real);
			booleantyp: (bval: boolean);
			chartyp:    (cval: char);
			symboltyp:  (sval: symbol)
		end;

	sym1 = record
		notempty: boolean;
		firstch: char;
		tail: symbol
		end;

(*	singlesub = ↑ss1;

	ss1 = record
		vr: variable;
		tm: term
		end;

	sub = ↑s1;

	s1 = record
		failed: boolean;
		isempty: boolean;
		first: singlesub;
		rest: sub
		end;
*)

(*Var x1, y1: termlist;
      x2, y2: term;
      s2: sub;
  Begin
	*initialize: s gets the empty substitution*
    new(s);
    s↑.isempty := true;
    s↑.failed := false;
    x1 := x;		(*these are here because they were in fwh's version*
    y1 := y;
    while x1↑.notempty and y1↑.notempty and not(s↑.failed) do
      begin
	termsubst( x1↑.first, s, x2);
	termsubst( y1↑.first, s, y2);
	if x2↑.ttyp = variable
	  then begin
		if y2↑.ttyp = variable
		  then begin
			if not( eqsym(x2↑.vr↑.pname, y2↑.vr↑.pname) )
			   (*pascal can't handle this comparison itself, records,you know*
			  then composesub( s, pair(x2↑.vr, y2));
			   (*if they are the same variable then nothing need be done*
		       end
		  else if occur(x2, y2)
			 then s↑.failed := true
			 else composesub( s, pair(x2↑.vr, y2))
	       end
	  else if y2↑.ttyp = variable
		 then begin
			if occur(y2, x2)
			  then s↑.failed := true
			  else composesub(s, pair(y2↑.vr, x2))
		      end
		 else if x2↑.ttyp = constant
			then begin
			       if y2↑.ttyp = constant
				 then begin
					if not( eqconst(x2↑.cnst, y2↑.cnst) )
					  then s↑.failed := true;
					  (*if they are = nothing need be done*
				      end
				 else if x2↑.cnst↑.ctyp = term
					then begin
					       matchconst(x2↑.const↑.tval, y2, s2);
					       if s2↑.failed
						 then s↑.failed := true
						 else composesub (s, s2)
					     end
					else s↑.failed := true;
					(*any other kind of constant could only
						match with a variable*
			     end
			else (*x2 is a funapp (thus of type term) and y2 is not a variable
			     if y2↑.ttyp = constant
				then begin
				       if y2↑.cnst↑.ctyp = term
					 then begin
						matchconst(y2↑.cnst↑.tval, x2, s2);
						if s2↑.failed
						  then s↑.failed := true
						  else composesub(s, s2)
					      end
					 else s↑.failed := true
				     end
				else (*x2 and y2 are both funapp terms*
				     if eqsym(x2↑.fname, y2↑.fname)
					then begin
						unify(x2↑.args, y2↑.args, s2);
						if s2↑.failed
						  then s↑.failed := true
						  else composesub(s, s2)
					     end
					else s↑.failed :=true;
	x1 := x1↑.rest;
	y1 := y1↑.rest
      end; (*of while*
    if x1↑.notempty or y1↑.notempty then s↑.failed := true
  End; (*of unify*
*)
(*unify side effects its args all over the place, the originals are copied before
the call is made*)
(*
Procedure unify(var x, y: termlist; failed:boolean);
  Var x1, y1: termlist;
      x2, y2: term;
      subfailed: boolean;
  Begin
	(*initialize*
    failed := false;
    x1 := x;
    y1 := y;
    while x1↑.notempty and y1↑.notempty and not(failed) do
      begin
	x2 := x1↑.first;
	y2 := y1↑.first;
	if x2↑.ttyp = variable
	  then begin
		if y2↑.ttyp = variable
		  then x2↑.vr↑.pname := y2↑.vr↑.pname
		    (* if they're already the same, the assignment is unnecessary
		     but cheaper than testing the equality and won't hurt anything*
		  else if occur(x2, y2)
			 then failed := true
			 else subst(x2↑.vr, y2, x, y)
	       end
	  else if y2↑.ttyp = variable
		 then begin
			if occur(y2, x2)
			  then failed := true
			  else subst(y2↑.vr, x2, x, y)
		      end
		 else if x2↑.ttyp = constant
			then begin
			       if y2↑.ttyp = constant
				 then begin
					if not( eqconst(x2↑.cnst, y2↑.cnst) )
					  then failed := true;
					  (*if they are = nothing need be done*
				      end
				 else if x2↑.cnst↑.ctyp = term
					then begin
					       matchconst(x2↑.const↑.tval, y2, x, y, subfailed);
					       if subfailed
						 then failed := true
					     end
					else failed := true;
					(*any other kind of constant could only
						match with a variable*
			     end
			else (*x2 is a funapp (thus of type term) and y2 is not a variable*
			     if y2↑.ttyp = constant
				then begin
				       if y2↑.cnst↑.ctyp = term
					 then begin
						matchconst(y2↑.cnst↑.tval, x2, x, y, subfailed);
						if subfailed
						  then failed := true
					      end
					 else failed := true
				     end
				else (*x2 and y2 are both funapp terms*
				     if eqsym(x2↑.fname, y2↑.fname)
					then begin
						unify(x2↑.args, y2↑.args, subfailed);
						if subfailed
						  then failed := true
					     end
					else failed :=true;
	x1 := x1↑.rest;
	y1 := y1↑.rest
      end; (*of while*
    if x1↑.notempty or y1↑.notempty then failed := true
  End; (*of unify*
*)

(* the true glory of the new type defs shows up here... no matchconst is necessary!
Procedure Matchconst(x, y, allx, ally: term; var failed: boolean);
  Var x1, y1: termlist;
      subfailed: boolean;
  Begin
    failed := false;
    if y↑.ttyp = variable 
      then subst(y↑.vr, x, allx, ally)
      else if y↑.ttyp = constant
	     then begin
		    if not(eqconst(x, y↑.cnst))
		      then failed := true
		  end (*if they're the same then nothing need be done*
	     else if x↑.ttyp = funapp
		    then begin
			   if eqsym(y↑.fname, x↑.fname)
			     then begin
				    x1 := x↑.args;
				    y1 := y↑.args;
				    while x1↑.notempty and y1↑.notempty and not(failed)
				      do begin
					   Matchconst(x1↑.first, y1↑.first, allx, ally, subfailed);
					   if subfailed
					     then failed := true
					 end
				  end
			     else failed := true
			 end
		    else failed := true
  End; (*matchconst*
*)

Function occur(x,y:term):boolean;
begin
occur:= true;
end;


Procedure Replace(x, t: term; var tml: termlist);
  Var tl1:termlist;
	t1:term;
  Begin
    tl1:= tml;
    while tl1↑.notempty do
    begin
      t1 := tl1↑.first;
      if not(t1↑.ttyp = constanttyp)
        then begin
	      if t1↑.ttyp = variable
	      then begin
		     if x↑.vr = t1↑.vr
		       then (*t1 gets t, but i dont think an assignment will work;
				try it anyway, think about it later*)
			    tl1↑.first := t (*need to mung record, not just ptr t1*)
		       (*else, no change needed*)
		   end
	      else (*it's a funapp*)
		   replace (x, t, tl1↑.first↑.args)
	   end;
      (*if its a constant no changes need be made*)
      tl1 := tml↑.rest
    end (*of while*)
  End; (*replace*)

Procedure Subst(x, t:term; var t1, t2:termlist);
Begin
  replace(x, t, t1);
  replace(x, t, t2)
End;


Function Eqsym(x,y:symbol):boolean;
Begin
  while x↑.notempty and y↑.notempty and (x↑.firstch = y↑.firstch) do
    begin
	x:=x↑.tail;
	y:=y↑.tail
    end;
  if x↑.notempty or y↑.notempty
    then eqsym:= false
    else eqsym:= true
End;


Function eqconst(x,y:constant):boolean;
Begin
  if x↑.ctyp = y↑.ctyp
    then case x↑.ctyp of
		integertyp: eqconst:= x↑.ival = y↑.ival;
		realtyp: eqconst:= x↑.rval = y↑.rval;
		booleantyp: eqconst:= x↑.bval = y↑.bval;
		chartyp: eqconst:= x↑.cval = y↑.cval;
		symboltyp: eqconst:= eqsym (x↑.sval, y↑.sval)
	 end
    else eqconst:= false
End;


Function Copysym(oldsym:symbol):symbol;
  Var newsym, lastnode, newnode:symbol;

  Begin
    new(newsym);
    lastnode := newsym;
    while oldsym↑.notempty do
    begin
      lastnode↑.notempty := true;
      lastnode↑.firstch := oldsym↑.firstch;
      new(newnode);
      lastnode↑.tail := newnode;
      lastnode := newnode;
      oldsym := oldsym↑.tail
    end;
    lastnode↑.notempty := false;
    copysym := newsym
  End; (*Copysym*)


Function Copyterm(oldtm:term):Term;
forward;


Function Copytermlist(tml:termlist):Termlist;
  Var newnode, lastnode, tmlnew:termlist;
	
  Begin
    new(tmlnew);
    lastnode := tmlnew;
    while tml↑.notempty do
    begin
      lastnode↑.notempty := true;
      lastnode↑.first := copyterm(tml↑.first);
      new(newnode);
      lastnode↑.rest := newnode;
      lastnode := newnode;
      tml := tml↑.rest;
    end;
    lastnode↑.notempty := false;
    copytermlist := tmlnew
  End; (*copytermlist*)


Function Copyconst(oldconst:constant):Constant;
  Var newconst:constant;

  Begin
    new(newconst);
    newconst↑.ctyp := oldconst↑.ctyp;
    case newconst↑.ctyp of
	integertyp: newconst↑.ival := oldconst↑.ival;
	realtyp: newconst↑.rval := oldconst↑.rval;
	booleantyp: newconst↑.bval := oldconst↑.bval;
	chartyp: newconst↑.cval := oldconst↑.cval;
	symboltyp: newconst↑.sval := copysym(oldconst↑.sval)
    end; (*of case stmt*)
    copyconst := newconst
  End; (*Copyconst*)


Function Copyterm;
  Var newtm:term;

  Begin
    new(newtm);
    newtm↑.ttyp := oldtm↑.ttyp;
    case newtm↑.ttyp of
	variable: newtm↑.vr := oldtm↑.vr; (*it's just an integer*)
	constanttyp: newtm↑.cnst := copyconst(oldtm↑.cnst);
	funapp:   begin
		    newtm↑.fname := copysym(oldtm↑.fname);
		    newtm↑.args := copytermlist(oldtm↑.args)
		  end
    end; (*of case stmt*)
    copyterm := newtm
  End; (*Copyterm*)							


(*the first call on unify will repeat the arglists being unified- dumb, but it
makes it possible to accomplish the substitutions by replacement as we go instead
of building a substitution and making new copies of everything every time we do
a substitution.  the allx and ally args are necessary to ensure that any replacements
resulting from recursive calls get made throughout the entire termlists you started
with*)
Procedure unify(var x, y, allx, ally: termlist; failed:boolean);
  Var x1, y1: termlist;
      x2, y2: term;
      subfailed: boolean;
  Begin
	(*initialize*)
    failed := false;
    x1 := x;
    y1 := y;
    while x1↑.notempty and y1↑.notempty and not(failed) do
      begin
	x2 := x1↑.first;
	y2 := y1↑.first;
	if x2↑.ttyp = variable
	  then begin
		if y2↑.ttyp = variable
		  then x2↑.vr := y2↑.vr
		    (* if they're already the same, the assignment is unnecessary
		     but cheaper than testing the equality and won't hurt anything*)
		  else if occur(x2, y2)
			 then failed := true
			 else subst(x2, y2, x, y)
	       end
	  else if y2↑.ttyp = variable
		 then begin
			if occur(y2, x2)
			  then failed := true
			  else subst(y2, x2, x, y)
		      end
		 else if x2↑.ttyp = constanttyp
			then begin
			       if y2↑.ttyp = constanttyp
				 then begin
					if not( eqconst(x2↑.cnst, y2↑.cnst) )
					  then failed := true;
					  (*if they are = nothing need be done*)
				      end
				 else failed := true
			     end
			else (*x2 is a funapp and y2 is not a variable*)
			     if y2↑.ttyp = constanttyp
				then failed := true
				else (*x2 and y2 are both funapp terms*)
				     if eqsym(x2↑.fname, y2↑.fname)
					then begin
						unify(x2↑.args, y2↑.args,
							allx, ally, subfailed);
						if subfailed
						  then failed := true
					     end
					else failed :=true;
	x1 := x1↑.rest;
	y1 := y1↑.rest
      end; (*of while*)
    if x1↑.notempty or y1↑.notempty then failed := true
  End; (*of unify*)

begin (*junk*)
end.